package robocup.component.tactics;

import java.util.LinkedList;

import robocup.component.RobocupAgent;
import robocup.component.infotypes.InfoReceiver;
import robocup.component.infotypes.PlayModeInfo;
import robocup.component.infotypes.PlayerSayInfo;
import robocup.component.infotypes.PlayerTypesInfo;
import robocup.component.infotypes.RefereeInfo;
import robocup.component.infotypes.SenseBodyInfo;
import robocup.component.infotypes.VisualInfo;
import robocup.component.math.RCMath;
import robocup.connection.TeamSoccerScopeMediator;

/**
 * @author wetzker
 *
 */
public class MyStateEval
    extends StateEvaluation implements InfoReceiver {

  /**
   * <code>savedStates</code> is used to memorize the executed states for an
   * agent in order to display them on the monitor, if this is used.
   */
  private final LinkedList<String> savedStates       = new LinkedList<String>();

  /**
   * <code>buffer</code> is used to generate the string of
   * <code>savedStates</code>.
   */
  private final StringBuffer       buffer            = new StringBuffer();
  
  /**
   * if true the calculation is stopped and no actions are send. This is set
   * true whenever a new BS arrives.
   */
  private boolean shouldStop = false;
  
  /**
   * if true we only calculate until we find the firt state with precon = true.
   */
  private boolean shouldHurry = false;

  /**
   * the best state found so far.
   */
  private AbstractState bestState;

  /**
   * Constructor.
   * 
   * @param tactic
   * @param agent
   */
  public MyStateEval(final RobocupAgent agent){
    super(agent);
  }

  /**
   * calculates the best state using the state evaluation and executes the
   * state.
   */
  private void calculateBestState() {
	this.cache.resetAll();
    this.shouldStop = false;
    this.shouldHurry = false;
    
    this.possibleStates.clear();    
    this.maxStateAssessment = 0.0;
    this.bestActions  = null;
    this.ball = this.getWorld().getBallRef();
    this.player = this.getWorld().getSelfRef();
    
    double currentAssessment;
    
    for (final AbstractState state : this.permanentStates) {
      //no more time -> take best state so far
      if(shouldHurry 
          && this.possibleStates.size()>0){
        break;
      }
      
      //actions were already sent
      if(this.shouldStop)
        return;
      
      state.reset();
      
      if(this.getProphet().getParent().getSynchro().wasSent()){
        break;
      }
      
      if (state.preCondition()) {
        currentAssessment = state.getStateAssessment();
        
        if(currentAssessment > this.maxStateAssessment){
          this.bestState = state;
          this.maxStateAssessment = currentAssessment;
        }
        
        if(!shouldStop)
          this.addPossibleStateToList(state);
      }
    }
    
    if(!this.agent.getSynchro().wasSent()){
      this.bestState.resetActions();
      this.bestState.calculateActions();
      this.agent.getSynchro().setActions(this.bestState.getActionSet());
      if (this.getAgent().useGui())
    	  this.saveStates();
      if(this.agent.getWorld().isViBased()){
        this.agent.informFinishedActing();
      }
    }
  }

  /**
   * if set we take the first state that returns an action
   */
  public void hurry(){
    this.shouldHurry = true;
  }
  
  /**
   * saves the states and assessment to the gui.
   *
   */
  private void saveStates() {

    this.savedStates.clear();

    for (final AbstractState state : this.world.getSelfRef()
        .getMyStateEval().getPossibleStates()) {
      this.buffer.setLength(0);
      this.buffer.append(
          Double.toString(RCMath.round(state.getStateAssessment(), 3))).append(
          "\t").append(state.getState().toString()).append("(").append(
          state.getSubStateString()).append(")");
      this.savedStates.add(this.buffer.toString());
    }
  }  
  
  /**
   * adds all possible states to the gui. called by the robocupagent after
   * sending actions
   */
  public void addStatesToGUI() {

    for (final String s : this.savedStates) {
      TeamSoccerScopeMediator.registerAddStateAss(s, this.agent);
    }
  }
  
  /* (non-Javadoc)
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.SenseBodyInfo)
   */
  public void update(final SenseBodyInfo info) {

    this.calculateBestState();
    
  }

  /* (non-Javadoc)
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.VisualInfo)
   */
  public void update(final VisualInfo info) {

    this.calculateBestState();
    
  }

  /* (non-Javadoc)
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.RefereeInfo)
   */
  public void update(final RefereeInfo info) {

    // TODO Auto-generated method stub
    
  }

  /* (non-Javadoc)
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.PlayModeInfo)
   */
  public void update(final PlayModeInfo info) {

    // TODO Auto-generated method stub
    
  }

  /* (non-Javadoc)
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.PlayerSayInfo)
   */
  public void update(final PlayerSayInfo info) {

    // TODO Auto-generated method stub
    
  }

  /* (non-Javadoc)
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.PlayerTypesInfo)
   */
  public void update(final PlayerTypesInfo info) {

    // TODO Auto-generated method stub
    
  }

  
  /**
   * stop calculations.
   *
   */
  public void stop(){
    this.shouldStop = true;
  }
}
